import Taro, { getCurrentPages } from '@tarojs/taro'
import {
  call, put, all, takeLatest, select
} from 'redux-saga/effects'
import { http } from '@pier88health/p8h-common'
import api from '@API'
import Storage from '@UTILS/storage'
import Navigate from '@NAVIGATION/navigateManager'
import { getPlatform, getClientType, showToast } from '@UTILS/common'
import {
  LOGOUT_USER,
  LOGIN_WEIXIN,
  VISITOR_LOGIN,
  REQUEST_AUTH_CODE,
  LOGIN_OR_REGISTER_BY_PHONE,
  WECHAT_LOGIN, CHECK_STATUS,
  SET_LOGIN_SUCCESS_INFO, GET_SYSTEM_CONFIG
} from '@ACTIONS/auth'
import {
  INIT_USER
} from '@ACTIONS/profile'
import { USER_STATUS } from '@CONSTANTS/profile'
import { GET_DEFAULT_PATIENT, GET_MY_PATIENTS } from '@ACTIONS/patient'
import { getAcquireChannelInfo } from '@UTILS/user'
import { UserITF } from '@INTERFACES/user'
import {
  AuthActionITF, AuthLoginParamsPayLoad,
  AuthLoginPayLoad,
  AuthRequestAuthCodePayLoad
} from '@REDUXITF/auth'
import { STORAGE_KEY } from '@CONSTANTS/common'
import { setGlobalData } from '@UTILS/globalData'
import { FIVE_MINUTES } from '@CONSTANTS/app'
import { getAuthInfo } from './dataSelect'

const LOGIN_STATUS_SUCCESS = 2
const saveUserToken = function* saveUserToken(UserToken: string) {
  Storage.getInstance().setToken(UserToken)
  Storage.getInstance().setLoginState(LOGIN_STATUS_SUCCESS)
  Taro.tracker.setUserId(UserToken)
  http.setToken(UserToken)
  yield Taro.setStorage({
    key: 'token',
    data: UserToken,
  })
}
const saveUserInfo = function* saveUserInfo(user: UserITF) {
  yield put({ type: INIT_USER.REQUEST, user })
  Taro.setStorage({
    key: 'user',
    data: user
  })
  setGlobalData('userAccount', user.UserName)
}
const loginAccountSuccess = function* loginAccountSuccess() {
  yield Taro.removeStorageSync(STORAGE_KEY.data_center_modal_key)
}

const saveUserOpenId = function saveUserOpenId(user: UserITF) {
  const { isWX } = getPlatform()
  if (!isWX) return
  Taro.setStorage({
    key: 'wx_openid',
    data: user.WeChat?.OpenId
  })
}

const loginSuccessJump = function* loginSuccessJump(double?: boolean) {
  try {
    const auth = yield select(getAuthInfo)
    const { lastSetLoginInfoTime, loginSuccess } = auth
    if (!loginSuccess) return
    const isTimeOut = lastSetLoginInfoTime && new Date().getTime() - lastSetLoginInfoTime > FIVE_MINUTES
    if (isTimeOut) return
    const time = double ? 500 : 0
    setTimeout(() => {
      loginSuccess?.()
    }, time)
    yield put({ type: SET_LOGIN_SUCCESS_INFO.REQUEST })
  } catch (e) {
    showToast(e)
  }
}
const loginWeiXin = function* loginWeiXin(action: AuthActionITF) {
  try {
    Taro.showLoading({
      title: '登录中',
    })
    const { payload, callback, disabledBack } = action.payload as AuthLoginPayLoad
    Object.assign(payload, getAcquireChannelInfo())
    const result = yield call(api.loginWithWeXinData, payload)
    Taro.hideLoading()
    const { UserToken } = result || {}
    if (!UserToken) {
      Taro.showToast({ icon: 'none', title: '微信登录失败' })
      return
    }
    yield saveUserToken(UserToken)
    yield saveUserInfo(result)
    yield saveUserOpenId(result)
    yield loginAccountSuccess()
    yield put({ type: LOGIN_WEIXIN.SUCCESS, result })
    yield put({ type: GET_DEFAULT_PATIENT.REQUEST })
    yield put({ type: GET_MY_PATIENTS.REQUEST })
    yield Taro.showToast({
      title: '登录成功',
      icon: 'success',
      duration: 1000
    })
    !disabledBack && (yield Navigate.navigateBack())
    if (callback) {
      callback?.()
      return
    }
    yield loginSuccessJump()
  } catch (error) {
    Taro.hideLoading()
    Taro.showToast({ icon: 'none', title: error.message || error })
    yield put({ type: LOGIN_WEIXIN.FAILURE })
  }
}

const requestAuthCode = function* requestAuthCode(action: AuthActionITF) {
  try {
    const payload = action.payload as AuthRequestAuthCodePayLoad
    const result = yield call(api.requestAuthCode, payload)
    const { ActionTokenId } = result
    yield put({ type: REQUEST_AUTH_CODE.SUCCESS, ActionTokenId })
  } catch (error) {
    Taro.showToast({ icon: 'none', title: error.message || error })
    yield put({ type: REQUEST_AUTH_CODE.FAILURE })
  }
}

const weChatLogin = function* weChatLogin(action: AuthActionITF) {
  try {
    const ClientType = getClientType()
    const payload = action.payload as AuthLoginParamsPayLoad
    Object.assign(payload, getAcquireChannelInfo())
    const user = yield call(api.loginWithWeChatInfo, { ...payload, ClientType })
    Taro.hideLoading()
    const { UserToken, Status } = user
    yield saveUserToken(UserToken)
    yield saveUserOpenId(user)
    yield Taro.setStorage({ key: 'user', data: user })
    setGlobalData('userAccount', user.UserName)
    if (Status === USER_STATUS.Registered) {
      yield put({ type: WECHAT_LOGIN.SUCCESS, user })
      yield put({ type: GET_DEFAULT_PATIENT.REQUEST })
      yield put({ type: GET_MY_PATIENTS.REQUEST })
      yield loginAccountSuccess()
      yield Taro.showToast({
        title: '登录成功',
        icon: 'success',
      })
      yield loginSuccessJump()
      return
    }
    yield put({ type: VISITOR_LOGIN.SUCCESS, user })
    Navigate.authPage()
  } catch (error) {
    Taro.hideLoading()
    Taro.showToast({ icon: 'none', title: error.message || error })
    yield put({ type: VISITOR_LOGIN.FAILURE })
  }
}
const loginOrRegisterByPhone = function* loginOrRegisterByPhone(action: AuthActionITF) {
  try {
    Taro.showLoading({
      title: '登录中',
      mask: true,
    })
    const ClientType = getClientType()
    const { payload: { double = false, ...params }, webCallback } = action.payload as AuthLoginPayLoad
    const { isWeb } = getPlatform()
    Object.assign(params, getAcquireChannelInfo())
    const result = yield call(api.loginOrRegisterByPhone, { ...params, ClientType })
    Taro.hideLoading()
    const { UserToken } = result
    yield saveUserToken(UserToken)
    yield saveUserInfo(result)
    yield saveUserOpenId(result)
    yield loginAccountSuccess()
    yield put({ type: LOGIN_OR_REGISTER_BY_PHONE.SUCCESS, result })
    yield put({ type: GET_DEFAULT_PATIENT.REQUEST })
    yield put({ type: GET_MY_PATIENTS.REQUEST })

    yield Taro.showToast({
      title: '登录成功',
      icon: 'success',
      duration: 1000,
    })
    isWeb ? webCallback?.() : (yield Navigate.navigateBack(double ? 2 : 1))
    yield loginSuccessJump(double)
  } catch (error) {
    Taro.hideLoading()
    Taro.showToast({ icon: 'none', title: error.message || error })
    yield put({ type: LOGIN_OR_REGISTER_BY_PHONE.FAILURE })
  }
}

const visitorLogin = function* visitorLogin(action?: AuthActionITF) {
  try {
    const { visitorLoginSuccess, payload: params = {} } = action || {}
    Object.assign(params, getAcquireChannelInfo())

    const user = yield call(api.visitorLogin, params)
    const { UserToken, Status } = user
    yield saveUserToken(UserToken)
    yield Taro.setStorage({ key: 'user', data: user })
    setGlobalData('userAccount', user.UserName)
    if (Status === USER_STATUS.Registered) {
      yield put({ type: LOGIN_OR_REGISTER_BY_PHONE.SUCCESS, result: user })
      yield put({ type: GET_DEFAULT_PATIENT.REQUEST })
      visitorLoginSuccess?.(user)
      return
    }
    yield put({ type: VISITOR_LOGIN.SUCCESS, user })
    visitorLoginSuccess?.(user)
  } catch (e) {
    yield Taro.showToast({ icon: 'none', title: e.message || e })
    yield put({ type: VISITOR_LOGIN.FAILURE })
  }
}

const logout = function* logout(action: AuthActionITF) {
  const { disableLogin } = action
  const { isWeb, isWX } = getPlatform()
  yield put({
    type: LOGOUT_USER.SUCCESS,
  })
  http.setToken('')
  Storage.getInstance().setToken(null)
  const data = Taro.getStorageSync(STORAGE_KEY.showLogGuideModal)
  yield Taro.clearStorage()
  Taro.setStorage({ key: STORAGE_KEY.showLogGuideModal, data })
  if (isWeb || isWX && getCurrentPages().length === 1) {
    Taro.removeTabBarBadge({ index: 1 })
  }
  if (disableLogin) {
    yield visitorLogin()
    return
  }
  if (isWeb) return
  yield Navigate.authPage()
}

const checkConsulationStatus = function* checkConsulationStatus() {
  try {
    const { isWX } = getPlatform()
    if (!isWX) return
    const { DisabledConsulation } = yield call(api.checkConsulationStatus, { isReviewVersion: '1.7.9' })
    yield put({ type: CHECK_STATUS.SUCCESS, DisabledConsulation })
  } catch (err) {
    yield put({ type: CHECK_STATUS.FAILURE, err })
  }
}

const getSystemConfig = function* getSystemConfig() {
  try {
    const result = yield call(api.getSystemConfig, { })
    yield put({ type: GET_SYSTEM_CONFIG.SUCCESS, result })
  } catch (err) {
    yield put({ type: GET_SYSTEM_CONFIG.FAILURE, err })
  }
}

export default function* rootSaga() : Generator {
  yield all([
    takeLatest(LOGIN_WEIXIN.REQUEST, loginWeiXin),
    takeLatest(REQUEST_AUTH_CODE.REQUEST, requestAuthCode),
    takeLatest(LOGIN_OR_REGISTER_BY_PHONE.REQUEST, loginOrRegisterByPhone),
    takeLatest(WECHAT_LOGIN.REQUEST, weChatLogin),
    takeLatest(LOGOUT_USER.REQUEST, logout),
    takeLatest(VISITOR_LOGIN.REQUEST, visitorLogin),
    takeLatest(CHECK_STATUS.REQUEST, checkConsulationStatus),
    takeLatest(GET_SYSTEM_CONFIG.REQUEST, getSystemConfig),
  ])
}
